#==================================================
# Author：	zhouweida
# Date ： 	2022/12/01
# License:	MIT
# usage:
#	1. 查找protobuf包 
#	2. 查找gRPC包
#	3. 生成proto源文件的函数
#
# 上下文变量含义
# _PROTOBUF_LIBPROTOBUF         = libprotobuf库
# _REFLECTION                   = gRPC::grpc++_reflection库
# _GRPC_GRPCPP                  = gRPC++ 库
# _PROTOBUF_PROTOC              = protoc程序
# _GRPC_CPP_PLUGIN_EXECUTABLE   = grpc_cpp_plugin程序
#==================================================

set(protobuf_MODULE_COMPATIBLE TRUE)
set(gRPC_USED TRUE) #是否使用gRPC

#protobuf
find_package(Protobuf CONFIG REQUIRED)
message(STATUS "Using protobuf ${Protobuf_VERSION}")
set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf)
if(CMAKE_CROSSCOMPILING)
  find_program(_PROTOBUF_PROTOC protoc)
else()
  set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)
  #set(_PROTOBUF_PROTOC ${PROTOBUF_PROTOC_EXECUTABLE})
endif()

#gRPC
if(gRPC_USED)
	set(_REFLECTION gRPC::grpc++_reflection)
	# Find gRPC installation
	# Looks for gRPCConfig.cmake file installed by gRPC's cmake installation.
	find_package(gRPC CONFIG REQUIRED)
	message(STATUS "Using gRPC ${gRPC_VERSION}")
	set(_GRPC_GRPCPP gRPC::grpc++)
	if(CMAKE_CROSSCOMPILING)
		find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin)
	else()
		set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>)
		#set(_GRPC_CPP_PLUGIN_EXECUTABLE gRPC::grpc_cpp_plugin)
	endif()
endif()

#
# _tg_name 					创建处理proto文件的自定义目标
# _PROTO_SRCS				由proto文件生成的cpp文件
# _PROTO_HDRS 				由proto文件生成的h文件
# PROTO_SEARCH_DIR 			proto文件的所在文件夹
# PROTO_OUTPUT_DIR			proto文件输出的文件夹
function(proto_gen_cpp _tg_name _PROTO_SRCS _PROTO_HDRS PROTO_SEARCH_DIR PROTO_OUTPUT_DIR)
    #设置输出路径
    if(EXISTS ${PROTO_OUTPUT_DIR} AND IS_DIRECTORY ${PROTO_OUTPUT_DIR})
            SET(PROTO_META_BASE_DIR ${PROTO_OUTPUT_DIR})
    else()
            file(MAKE_DIRECTORY ${PROTO_OUTPUT_DIR})
            SET(PROTO_META_BASE_DIR ${PROTO_OUTPUT_DIR})
    endif()

    #设置protoc的搜索路径
    LIST(APPEND PROTO_FLAGS -I${PROTO_SEARCH_DIR})
    #获取需要编译的proto文件
    file(GLOB_RECURSE PROTO_FILES ${PROTO_SEARCH_DIR}/*.proto)
    set(${_PROTO_SRCS})
    set(${_PROTO_HDRS})
    set(_file_names)
	set(temp_grpc_srcs)
	set(temp_grpc_hdrs)
    foreach(_file ${PROTO_FILES})
            get_filename_component(FIL_WE ${_file} NAME_WE)
            list(APPEND ${_PROTO_SRCS} "${PROTO_META_BASE_DIR}/${FIL_WE}.pb.cc" )
            list(APPEND ${_PROTO_HDRS} "${PROTO_META_BASE_DIR}/${FIL_WE}.pb.h" )
			if(gRPC_USED)
				list(APPEND temp_grpc_srcs "${PROTO_META_BASE_DIR}/${FIL_WE}.grpc.pb.cc" )
				list(APPEND temp_grpc_hdrs "${PROTO_META_BASE_DIR}/${FIL_WE}.grpc.pb.h" )
			endif()	
            list(APPEND _file_names  ${FIL_WE})
			list(APPEND _file_paths ${_file})
    endforeach()
    # 使用自定义命令
	message(STATUS ${PROTO_META_BASE_DIR})
	if(gRPC_USED)
		add_custom_command(
			OUTPUT ${${_PROTO_SRCS}} ${${_PROTO_HDRS}} ${temp_grpc_srcs} ${temp_grpc_hdrs}
			COMMAND  ${_PROTOBUF_PROTOC}
			ARGS --grpc_out "${PROTO_META_BASE_DIR}"
				--cpp_out  "${PROTO_META_BASE_DIR}"
				-I ${PROTO_SEARCH_DIR}
				--plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}"
				"${PROTO_FILES}"
			DEPENDS "${PROTO_FILES}"
			COMMENT "Running C++ protocol buffer compiler on { ${_file_names} }")
	else()
		add_custom_command(
			OUTPUT ${${_PROTO_SRCS}} ${${_PROTO_HDRS}}
			COMMAND  ${_PROTOBUF_PROTOC}
			ARGS --cpp_out  ${PROTO_META_BASE_DIR}
				-I ${PROTO_SEARCH_DIR}
				${PROTO_FILES}
			DEPENDS ${PROTO_FILES}
			COMMENT "Running C++ protocol buffer compiler on { ${_file_names} } ")
	endif()

    # 设置文件属性为 GENERATED，避免构建阶段目标找不到文件
    set_source_files_properties(${${_PROTO_SRCS}} ${${_PROTO_HDRS}} PROPERTIES GENERATED TRUE)

    # 添加自定义target
    add_custom_target(Proto_Gen_cpp_${_tg_name} ALL
                    DEPENDS ${${_PROTO_SRCS}} ${${_PROTO_HDRS}}
                    COMMENT "generate proto cpp target"
                    SOURCES ${${_PROTO_SRCS}} ${${_PROTO_HDRS}}
                    VERBATIM)
endfunction()